using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Drawing;
using EjemploDirectX.TgcViewer.Utils.TgcSceneLoader;

namespace TgcViewer.Utils.TgcSceneLoader
{
    /// <summary>
    /// Parser de XML de escena creado con plugin TgcSceneExporter.ms de 3DsMax
    /// </summary>
    public class TgcSceneParser
    {
        /// <summary>
        /// Levanta la informacion del XML
        /// </summary>
        /// <param name="xmlString">contenido del XML</param>
        /// <returns></returns>
        public TgcSceneData parseSceneFromString(string xmlString)
        {
            XmlDocument dom = new XmlDocument();
            dom.LoadXml(xmlString);
            XmlElement root = dom.DocumentElement;

            string sceneName = root.GetElementsByTagName("name")[0].InnerText;
            TgcSceneData tgcSceneData = new TgcSceneData();
            tgcSceneData.name = sceneName;

            //Ver si tiene exportacion de texturas
            XmlNode texturesExportNode = root.GetElementsByTagName("texturesExport")[0];
            bool texturesExportEnabled = bool.Parse(texturesExportNode.Attributes["enabled"].InnerText);
            if (texturesExportEnabled)
            {
                tgcSceneData.texturesDir = texturesExportNode.Attributes["dir"].InnerText;
            }

            //Ver si tiene LightMaps
            XmlNode lightmapsExportNode = root.GetElementsByTagName("lightmapExport")[0];
            tgcSceneData.lightmapsEnabled = bool.Parse(lightmapsExportNode.Attributes["enabled"].InnerText);
            if (tgcSceneData.lightmapsEnabled)
            {
                tgcSceneData.lightmapsDir = lightmapsExportNode.Attributes["dir"].InnerText;
            }


            //Parsear Texturas
            XmlNodeList materialNodes = root.GetElementsByTagName("materials")[0].ChildNodes;
            tgcSceneData.materialsData = new TgcMaterialData[materialNodes.Count];
            int i = 0;
            foreach (XmlElement matNode in materialNodes)
            {
                //determinar tipo de Material
                TgcMaterialData material = new TgcMaterialData();
                material.type = matNode.Attributes["type"].InnerText;

                //Standard Material
                if (material.type.Equals(TgcMaterialData.StandardMaterial))
                {
                    parseStandardMaterial(material, matNode);

                }

                //Multi Material
                else if (material.type.Equals(TgcMaterialData.MultiMaterial))
                {
                    material.name = matNode.Attributes["name"].InnerText;
                    XmlNodeList subMaterialsNodes = matNode.GetElementsByTagName("subM");
                    material.subMaterials = new TgcMaterialData[subMaterialsNodes.Count];
                    for (int j = 0; j < subMaterialsNodes.Count; j++)
                    {
                        TgcMaterialData subMaterial = new TgcMaterialData();
                        parseStandardMaterial(subMaterial, (XmlElement)subMaterialsNodes[j]);
                        material.subMaterials[j] = subMaterial;
                    }
                }

                tgcSceneData.materialsData[i++] = material;
            }



            //Parsear Meshes
            XmlNodeList meshesNodes = root.GetElementsByTagName("meshes")[0].ChildNodes;
            tgcSceneData.meshesData = new TgcMeshData[meshesNodes.Count];
            i = 0;
            foreach (XmlElement meshNode in meshesNodes)
            {
                TgcMeshData meshData = new TgcMeshData();
                tgcSceneData.meshesData[i++] = meshData;

                //parser y convertir valores
                meshData.name = meshNode.Attributes["name"].InnerText;
                meshData.materialId = int.Parse(meshNode.Attributes["matId"].InnerText);
                meshData.color = TgcParserUtils.parseFloat3Array(meshNode.Attributes["color"].InnerText);
                meshData.lightmap = meshNode.Attributes["lightmap"].InnerText;

                //TODO: formatear bien visibility y posicion
                string posStr = meshNode.Attributes["pos"].InnerText;
                string visibilityStr = meshNode.Attributes["visibility"].InnerText;
                int count;

                //parsear coordinatesIdx
                XmlNode coordinatesIdxNode = meshNode.GetElementsByTagName("coordinatesIdx")[0];
                count = int.Parse(coordinatesIdxNode.Attributes["count"].InnerText);
                meshData.coordinatesIndices = TgcParserUtils.parseIntStream(coordinatesIdxNode.InnerText, count);

                //parsear textCoordsIdx
                XmlNode textCoordsIdxNode = meshNode.GetElementsByTagName("textCoordsIdx")[0];
                count = int.Parse(textCoordsIdxNode.Attributes["count"].InnerText);
                meshData.texCoordinatesIndices = TgcParserUtils.parseIntStream(textCoordsIdxNode.InnerText, count);

                //parsear colorsIdx
                XmlNode colorsIdxNode = meshNode.GetElementsByTagName("colorsIdx")[0];
                count = int.Parse(colorsIdxNode.Attributes["count"].InnerText);
                meshData.colorIndices = TgcParserUtils.parseIntStream(colorsIdxNode.InnerText, count);

                //parsear matIds
                //TODO: ver bien como calcula esto el SCRIPT de Exportacion
                if (/*meshData.materialId > 0*/true)
                {
                    XmlNode matIdsNode = meshNode.GetElementsByTagName("matIds")[0];
                    count = int.Parse(matIdsNode.Attributes["count"].InnerText);
                    meshData.materialsIds = TgcParserUtils.parseIntStream(matIdsNode.InnerText, count);
                }

                //parsear textCoordsLightMapIdx
                if (tgcSceneData.lightmapsEnabled)
                {
                    XmlNode textCoordsLightMapIdxNode = meshNode.GetElementsByTagName("textCoordsLightMapIdx")[0];
                    count = int.Parse(textCoordsLightMapIdxNode.Attributes["count"].InnerText);
                    meshData.texCoordinatesIndicesLightMap = TgcParserUtils.parseIntStream(textCoordsLightMapIdxNode.InnerText, count);
                }
                

                //parsear vertices
                XmlNode verticesNode = meshNode.GetElementsByTagName("vertices")[0];
                count = int.Parse(verticesNode.Attributes["count"].InnerText);
                meshData.verticesCoordinates = TgcParserUtils.parseFloatStream(verticesNode.InnerText, count);

                //parsear normals
                XmlNode normalsNode = meshNode.GetElementsByTagName("normals")[0];
                count = int.Parse(normalsNode.Attributes["count"].InnerText);
                meshData.verticesNormals = TgcParserUtils.parseFloatStream(normalsNode.InnerText, count);

                //parsear texCoords
                XmlNode texCoordsNode = meshNode.GetElementsByTagName("texCoords")[0];
                count = int.Parse(texCoordsNode.Attributes["count"].InnerText);
                meshData.textureCoordinates = TgcParserUtils.parseFloatStream(texCoordsNode.InnerText, count);

                //parsear colors
                XmlNode colorsNode = meshNode.GetElementsByTagName("colors")[0];
                count = int.Parse(colorsNode.Attributes["count"].InnerText);
                float[] colorsArray = TgcParserUtils.parseFloatStream(colorsNode.InnerText, count);
                //convertir a format TV
                meshData.verticesColors = new int[count / 3];
                for (int j = 0; j < meshData.verticesColors.Length; j++)
                {
                    meshData.verticesColors[j] = Color.FromArgb(
                        (int)colorsArray[j * 3],
                        (int)colorsArray[j * 3 + 1],
                        (int)colorsArray[j * 3 + 2]).ToArgb();
                }

                //parsear texCoordsLightMap
                if (tgcSceneData.lightmapsEnabled)
                {
                    XmlNode texCoordsLightMapNode = meshNode.GetElementsByTagName("texCoordsLightMap")[0];
                    count = int.Parse(texCoordsLightMapNode.Attributes["count"].InnerText);
                    meshData.textureCoordinatesLightMap = TgcParserUtils.parseFloatStream(texCoordsLightMapNode.InnerText, count);
                }

            }

            return tgcSceneData;
        }

        private void parseStandardMaterial(TgcMaterialData material, XmlElement matNode)
        {
            material.name = matNode.Attributes["name"].InnerText;
            material.type = matNode.Attributes["type"].InnerText;

            //Valores de Material
            string ambientStr = matNode.GetElementsByTagName("ambient")[0].InnerText;
            material.ambientColor = TgcParserUtils.parseFloat4Array(ambientStr);
            TgcParserUtils.divFloatArrayValues(ref material.ambientColor, 255f);

            string diffuseStr = matNode.GetElementsByTagName("diffuse")[0].InnerText;
            material.diffuseColor = TgcParserUtils.parseFloat4Array(diffuseStr);
            TgcParserUtils.divFloatArrayValues(ref material.diffuseColor, 255f);

            string specularStr = matNode.GetElementsByTagName("specular")[0].InnerText;
            material.specularColor = TgcParserUtils.parseFloat4Array(specularStr);
            TgcParserUtils.divFloatArrayValues(ref material.specularColor, 255f);

            string opacityStr = matNode.GetElementsByTagName("opacity")[0].InnerText;
            material.opacity = TgcParserUtils.parseFloat(opacityStr) / 100f;


            //Valores de Bitmap
            XmlNode bitmapNode = matNode.GetElementsByTagName("bitmap")[0];
            if (bitmapNode != null)
            {
                material.fileName = bitmapNode.InnerText;

                //TODO: formatear correctamente TILING y OFFSET
                string uvTilingStr = bitmapNode.Attributes["uvTiling"].InnerText;
                material.uvTiling = TgcParserUtils.parseFloat2Array(uvTilingStr);

                string uvOffsetStr = bitmapNode.Attributes["uvOffset"].InnerText;
                material.uvOffset = TgcParserUtils.parseFloat2Array(uvOffsetStr);
            }
            else
            {
                material.fileName = null;
                material.uvTiling = null;
                material.uvOffset = null;
            }
        }


    }
}
